﻿using System;
using System.Collections.Generic;
using System.Threading;
using fastCSharp;
using fastCSharp.threading;

namespace OnlineJudge
{
    /// <summary>
    /// OJ路由服务
    /// </summary>
    [fastCSharp.code.cSharp.tcpServer(Service = "OJRouter", IsIdentityCommand = true, IsServerAsynchronousReceive = false, IsCompress = true, IsMarkData = true, IsSegmentation = true, ClientSegmentationCopyPath = @"C:\diantou\OnlineJudgeClient\", VerifyMethodType = typeof(tcpClient.RouterServer.tcpClient.timeVerifyMethod), ClientSendSleep = 1, ServerSendSleep = 1)]
    public partial class RouterServer : fastCSharp.net.tcp.timeVerifyServer, IDisposable
    {
        /// <summary>
        /// 回调类型数量
        /// </summary>
        private static readonly int callbackSize = fastCSharp.Enum.GetMaxValue<RouterCallback>(-1) + 1;
        /// <summary>
        /// OJ路由
        /// </summary>
        private Router router;
        /// <summary>
        /// 测试队列
        /// </summary>
        private collection<JudgeReportBase> judges;
        /// <summary>
        /// 测试队列访问锁
        /// </summary>
        private readonly object judgeLock = new object();
        /// <summary>
        /// 测试回调
        /// </summary>
        internal Func<fastCSharp.net.returnValue<JudgeItemBase>, bool>[] OnJudgeItems = new Func<fastCSharp.net.returnValue<JudgeItemBase>, bool>[callbackSize];
        /// <summary>
        /// 测试回调
        /// </summary>
        internal Func<fastCSharp.net.returnValue<JudgeReportBase>, bool>[] OnJudgeReports = new Func<fastCSharp.net.returnValue<JudgeReportBase>, bool>[callbackSize];
        /// <summary>
        /// 设置TCP服务端
        /// </summary>
        /// <param name="tcpServer">TCP服务端</param>
        public override void SetCommandServer(fastCSharp.net.tcp.commandServer tcpServer)
        {
            base.SetCommandServer(tcpServer);
            judges = new collection<JudgeReportBase>();
            router = new Router(this);
        }
        /// <summary>
        /// 释放资源
        /// </summary>
        public void Dispose()
        {
            pub.Dispose(ref router);
            Array.Clear(OnJudgeItems, 0, callbackSize);
            Array.Clear(OnJudgeReports, 0, callbackSize);
            Monitor.Enter(judgeLock);
            judges.Clear();
            Monitor.Exit(judgeLock);
        }
        /// <summary>
        /// 添加测试
        /// </summary>
        /// <param name="item"></param>
        [fastCSharp.code.cSharp.tcpMethod]
        private void judge(JudgeReportBase item)
        {
            switch (item.CompileType)
            {
                case CompileType.CompileSolution:
                case CompileType.CompileSpecialJudge:
                    foreach (OnlineJudge.tcpClient.Server.tcpClient client in router.GetAll()) client.judge(item);
                    return;
            }
            JudgeCount judgeCount = router.GetMinClient();
            if (judgeCount != null)
            {
                try
                {
                    if (judgeCount.Judge(item)) return;
                }
                catch { }
            }
            Monitor.Enter(judgeLock);
            try
            {
                judges.Add(item);
            }
            finally { Monitor.Exit(judgeLock); }
        }
        /// <summary>
        /// 测试调用错误
        /// </summary>
        /// <param name="judge"></param>
        public void ErrorJudge(JudgeReportBase judge)
        {
            Monitor.Enter(judgeLock);
            try
            {
                judges.AddExpand(judge);
            }
            finally { Monitor.Exit(judgeLock); }
        }
        /// <summary>
        /// 测试调用错误
        /// </summary>
        /// <param name="judges"></param>
        public void ErrorJudge(subArray<JudgeReportBase> judges)
        {
            Monitor.Enter(judgeLock);
            try
            {
                judges.Add(judges);
            }
            finally { Monitor.Exit(judgeLock); }
        }
        /// <summary>
        /// 获取测试
        /// </summary>
        /// <returns></returns>
        public JudgeReportBase GetNextJudge()
        {
            Monitor.Enter(judgeLock);
            if (judges.Count == 0)
            {
                Monitor.Exit(judgeLock);
                return null;
            }
            JudgeReportBase value = judges.PopExpand();
            Monitor.Exit(judgeLock);
            return value;
        }
        /// <summary>
        /// 测试回调
        /// </summary>
        /// <param name="onJudged"></param>
        [fastCSharp.code.cSharp.tcpMethod(IsServerAsynchronousCallback = true, IsClientAsynchronous = true, IsClientCallbackTask = false, IsClientSynchronous = false, IsKeepCallback = true)]
        private void onJudged(RouterCallback callback, Func<fastCSharp.net.returnValue<JudgeItemBase>, bool> onJudged)
        {
            OnJudgeItems[(byte)callback] = onJudged;
        }
        /// <summary>
        /// 测试回调
        /// </summary>
        /// <param name="onJudged"></param>
        [fastCSharp.code.cSharp.tcpMethod(IsServerAsynchronousCallback = true, IsClientAsynchronous = true, IsClientCallbackTask = false, IsClientSynchronous = false, IsKeepCallback = true)]
        private void onJudged(RouterCallback callback, Func<fastCSharp.net.returnValue<JudgeReportBase>, bool> onJudged)
        {
            OnJudgeReports[(byte)callback] = onJudged;
        }
        /// <summary>
        /// 添加或者修改测试数据
        /// </summary>
        /// <param name="problemId"></param>
        /// <param name="testId"></param>
        /// <param name="inData"></param>
        /// <param name="outData"></param>
        /// <returns></returns>
        [fastCSharp.code.cSharp.tcpMethod]
        private void testData(int problemId, int testId, string inData, string outData, DateTime problemTime)
        {
            foreach (OnlineJudge.tcpClient.Server.tcpClient client in router.GetAll()) client.testData(problemId, testId, inData, outData, problemTime);
        }
        /// <summary>
        /// 删除测试数据
        /// </summary>
        /// <param name="problemId"></param>
        /// <param name="testId"></param>
        /// <returns></returns>
        [fastCSharp.code.cSharp.tcpMethod]
        private void deleteTestData(int problemId, int testId, DateTime problemTime)
        {
            foreach (OnlineJudge.tcpClient.Server.tcpClient client in router.GetAll()) client.deleteTestData(problemId, testId, problemTime);
        }
        /// <summary>
        /// 设置问题测试参数
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        [fastCSharp.code.cSharp.tcpMethod]
        private void setProblemJudgeSetting(JudgeSetting value, DateTime problemTime)
        {
            foreach (OnlineJudge.tcpClient.Server.tcpClient client in router.GetAll()) client.setProblemJudgeSetting(value, problemTime);
        }
        /// <summary>
        /// 删除特判程序
        /// </summary>
        /// <param name="problemId"></param>
        /// <returns></returns>
        [fastCSharp.code.cSharp.tcpMethod]
        private void deleteSpecialProgarm(int problemId, DateTime problemTime)
        {
            foreach (OnlineJudge.tcpClient.Server.tcpClient client in router.GetAll()) client.deleteSpecialProgarm(problemId, problemTime);
        }
        /// <summary>
        /// 更新题目时间
        /// </summary>
        /// <param name="problemId"></param>
        /// <param name="problemTime">问题更新时间</param>
        /// <returns></returns>
        [fastCSharp.code.cSharp.tcpMethod]
        private void reworkProblemTime(int problemId, DateTime problemTime)
        {
            foreach (OnlineJudge.tcpClient.Server.tcpClient client in router.GetAll()) client.reworkProblemTime(problemId, problemTime);
        }
        /// <summary>
        /// 更新OJ数据
        /// </summary>
        /// <param name="data"></param>
        [fastCSharp.code.cSharp.tcpMethod]
        private void reworkProblemData(OnlineJudge.problemData data, DateTime problemTime)
        {
            foreach (OnlineJudge.tcpClient.Server.tcpClient client in router.GetAll()) client.reworkProblemData(data, problemTime);
        }
        /// <summary>
        /// 输入数据格式化字符串检测
        /// </summary>
        /// <param name="formatString"></param>
        /// <returns></returns>
        [fastCSharp.code.cSharp.tcpMethod]
        private bool checkFormatString(string formatString)
        {
            return router.GetRandomClient().Client.checkFormatString(formatString);
        }
        /// <summary>
        /// 题目更新时间回调
        /// </summary>
        internal Func<fastCSharp.net.returnValue<bool>, bool> CheckProblemTime;
        /// <summary>
        /// 题目更新时间回调
        /// </summary>
        /// <param name="checkProblemTime"></param>
        [fastCSharp.code.cSharp.tcpMethod(IsServerAsynchronousCallback = true, IsClientAsynchronous = true, IsClientCallbackTask = false, IsClientSynchronous = false, IsKeepCallback = true)]
        private void checkProblemTime(Func<fastCSharp.net.returnValue<bool>, bool> checkProblemTime)
        {
            CheckProblemTime = checkProblemTime;
        }
   }
}
